//////////////////////////////////////////////////////////////////////////
#pragma once


//////////////////////////////////////////////////////////////////////////
#include "Math/Math.hpp"


namespace Math
{
	class Vector3f;
	class Matrix44f;

	class Quaternionf
	{
	public:
		// Element index's.
		static const size_t						kXIndex		=	0;
		static const size_t						kYIndex		=	1;
		static const size_t						kZIndex		=	2;
		static const size_t						kWIndex		=	3;

		// Pull the type from the base Simd definition.
		typedef Quaternionf						ValueType_t;
		typedef const Quaternionf&				ParamType_t;

		// Construction.
		Quaternionf();
		Quaternionf( const Quaternionf& rhs );
		Quaternionf( float x, float y, float z, float w );

		// Accessors.
		float						X() const;
		float						Y() const;
		float						Z() const;
		float						W() const;
		void						X( float x );
		void						Y( float y );
		void						Z( float z );
		void						W( float w );

		// Array accessors.
		float						operator ()( size_t idx ) const;
		void						operator ()( size_t idx, float v );

		//
		bool						operator ==( const Quaternionf& rhs ) const;
		bool						operator !=( const Quaternionf& rhs ) const;

		// Assignments.
		void						Set( float x, float y, float z, float w );
		const Quaternionf&			operator =( const Quaternionf& rhs );

		// Operator overloads.
		Quaternionf					operator -() const;
		Quaternionf					operator +( const Math::Quaternionf& rhs ) const;
		Quaternionf					operator *( const Quaternionf& rhs ) const;
		Quaternionf					operator *( const float rhs ) const;
		void						operator +=( const Math::Quaternionf& rhs );
		void						operator *=( const Quaternionf& rhs );

		// Member functions.
		void						Normalize();
		void						Inverse();
		void						Conjugate();

		// Static initializers.
		static Quaternionf			Zero();
		static Quaternionf			Identity();
		static Quaternionf			Rotation( const Vector3f& axis, float rot );
		static Quaternionf			From( const Matrix44f& rhs );

	private:
		// Implementation data.
		float						mX;
		float						mY;
		float						mZ;
		float						mW;
	};


	inline Vector3f					operator *( const Quaternionf& lhs, const Math::Vector3f& rhs );

	inline float					Dot( const Quaternionf& lhs, const Quaternionf& rhs );
	inline Quaternionf				Normalize( const Quaternionf& rhs );
	inline Quaternionf				Inverse( const Quaternionf& rhs );
	inline Quaternionf				Conjugate( const Quaternionf& rhs );
	inline float					Norm( const Quaternionf& rhs );
	inline Quaternionf				Slerp( const Quaternionf& lhs, const Quaternionf& rhs, float p );
	inline float					DeltaAngle( const Quaternionf& lhs, const Quaternionf& rhs );
	inline float					ArcDelta( const Quaternionf& lhs, const Quaternionf& rhs, const Vector3f& axis );
	inline Quaternionf				RotationTo( const Math::Vector3f& from, const Math::Vector3f& to );
}


// Include the implementations.
#include "Detail/Quaternionf_Impl.hpp"
